﻿using System;
using System.Drawing;

namespace Segmentation.Business
{
    static class GaussianNoise
    {
        private const int MINCOMPENENTVALUE = 0;
        private const int MAXCOMPENENTVALUE = 255;

        public static Bitmap AddNoise(Bitmap bitmap, double psnr)
        {
            double variance = Math.Pow(MAXCOMPENENTVALUE / psnr, 2);

            int[] matrix = new int[bitmap.Height * bitmap.Width * 3];

            for (int x = 0, i = 0; x < bitmap.Width; x++)
            {
                for (int y = 0; y < bitmap.Height; y++)
                {
                    Color colorOriginal = bitmap.GetPixel(x, y);
                    int red = colorOriginal.R + Convert.ToInt32(NormalDistribution.GetNext(variance));
                    int green = colorOriginal.G + Convert.ToInt32(NormalDistribution.GetNext(variance));
                    int blue = colorOriginal.B + Convert.ToInt32(NormalDistribution.GetNext(variance));

                    matrix[i++] = red;
                    matrix[i++] = green;
                    matrix[i++] = blue;
                }
            }
            int min = matrix[0];
            int max = matrix[0];
            foreach (int value in matrix)
            {
                if (min > value)
                    min = value;
                else if (max < value)
                    max = value;
            }

            if (min < MINCOMPENENTVALUE)
            {
                max -= min;
                for (int i = 0; i < matrix.Length; i++)
                {
                    matrix[i] -= min;
                }
            }

            if (max > MAXCOMPENENTVALUE)
            {
                for (int i = 0; i < matrix.Length; i++)
                {
                    matrix[i] = (matrix[i] * MAXCOMPENENTVALUE) / max;
                }
            }

            Bitmap noisedBitmap = new Bitmap(bitmap);
            for (int x = 0, i = 0; x < bitmap.Width; x++)
            {
                for (int y = 0; y < bitmap.Height; y++)
                {
                    noisedBitmap.SetPixel(x, y, Color.FromArgb(matrix[i++], matrix[i++], matrix[i++]));
                }
            }
            return noisedBitmap;
        }
    }
}
